#include "app_porting.h"

//#define FP_TASK_DEBUG_ENABLE

#define FP_RECEIVE_TIMEOUT 1000
#define FP_DATA_LEN 30

uint8_t fp_receive_buf[FP_DATA_LEN+INNER_PAD_LEN];
uint8_t fp_send_buf[FP_DATA_LEN+INNER_PAD_LEN];

YTDSP_INFO_T g_ytdsp_info;

typedef enum{
	LED_NETWORK_BIT=1<<0,
	LED_GPS_BIT=1<<1,
	LED_YTIS_BIT=1<<2,
	LED_PID_BIT=1<<3,	
	
	BEEP_BIT=1<<7,
}BEEP_LED_BIT_E;

typedef struct{
	uint8_t seg[SEG_LEN];
	uint8_t beep_led;
}FP_CONTROL_T;

static FP_CONTROL_T sg_fp;

void fp_led_network(bool on)
{
	if(TRUE==on){
		sg_fp.beep_led|=LED_NETWORK_BIT;
	}else{
		sg_fp.beep_led&=~LED_NETWORK_BIT;
	}
}

void fp_led_gps(bool on)
{
	if(TRUE==on){
		sg_fp.beep_led|=LED_GPS_BIT;
	}else{
		sg_fp.beep_led&=~LED_GPS_BIT;
	}
}

void fp_led_ytis(bool on)
{
	if(TRUE==on){
		sg_fp.beep_led|=LED_YTIS_BIT;
	}else{
		sg_fp.beep_led&=~LED_YTIS_BIT;
	}
}

void fp_led_pid(bool on)
{
	if(TRUE==on){
		sg_fp.beep_led|=LED_PID_BIT;
	}else{
		sg_fp.beep_led&=~LED_PID_BIT;
	}
}

void fp_beep(bool on)
{
	if(TRUE==on){
		sg_fp.beep_led|=BEEP_BIT;
	}else{
		sg_fp.beep_led&=~BEEP_BIT;
	}
}


static const unsigned char sNumTbl[10] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f}; 

static const unsigned char sChrTblUp[26] = {

    0x77, 0x7f, 0x39, 0x3f, 0x79, 0x71, 0x3d, 0x76, 0x06, 0x07,  /* A -> J */

    0x36, 0x38, 0x4f, 0x37, 0x3f, 0x73, 0xff,0x77, 0x6d, 0x31,  /* K -> T */

    0x3e, 0x3e, 0x4f, 0x76, 0x72, 0x5b                                       /* U -> Z */

};

static const unsigned char sChrTblLow[26] = {

    0x5c, 0x7c, 0x58, 0x5e, 0x7b, 0x71, 0x6f, 0x74, 0x05, 0x0d,  /* a -> j */

    0x70, 0x30, 0x4f, 0x54, 0x5c, 0x73, 0x67, 0x50, 0x6d, 0x78,  /* k -> t */

    0x1c, 0x1c, 0x4f, 0x76, 0x6e, 0x5b                                       /* u -> z */

};

void panel_display(uint8_t *fpString)
{
	uint8_t  DispCode[SEG_LEN] = {0};
	uint8_t j;

	memcpy(DispCode, fpString, SEG_LEN);
	
	for(j=0;j< SEG_LEN;j++)
	{
		if ((DispCode[j]>='A')&&(DispCode[j]<='Z'))
		{
			DispCode[j] = sChrTblUp[DispCode[j]-'A'];
		}
		else if ((DispCode[j]>='a')&&(DispCode[j]<='z'))
		{
			DispCode[j] = sChrTblLow[DispCode[j]-'a'];
		}
		else if((DispCode[j]>='0')&&(DispCode[j]<='9'))
		{
			DispCode[j] = sNumTbl[DispCode[j]-'0'];
		}
		else if (DispCode[j] == '-')
		{
			DispCode[j] = 0x40; 
		}
		else if (DispCode[j] == '_')
		{
			DispCode[j] = 0x08;
		}
		else if (DispCode[j] == '.')
		{
			DispCode[j]=0x80;
		}
		else  /* FIXME: may be should add symbol ':' and '.' */
		{
			DispCode[j] = 0;  /* default: not display */
		}
	}

	memcpy(sg_fp.seg,DispCode,SEG_LEN);
}

int32_t fp_display(void)
{
#ifdef FP_TASK_DEBUG_ENABLE
	int32_t i;
#endif
	int32_t len;
	
	len=inner_wrapper(fp_send_buf,sizeof(fp_send_buf),DSPCMD_FP_SEND,(uint8_t*)&sg_fp,sizeof(FP_CONTROL_T));
	if(len<INNER_PAD_LEN){
		
		return LS_FAIL;
	}

#ifdef FP_TASK_DEBUG_ENABLE
	printf("fp_send[%d]={",len);
	for(i=0;i<len;i++){
		printf("0x%02x,",fp_send_buf[i]);
	}
	printf("}\r\n");
#endif
	return uart_transmit_buf(FP_DEVICE,fp_send_buf,len);
}

int32_t fp_keys_parse(uint8_t *pdata, int32_t data_len, KEY_RAW_T *praw)
{
	int32_t i;
	int32_t ret;
	
	if(NULL==pdata || data_len<=0)	{
		return LS_FAIL;
	}	

//sn	
	i=0;
	ret=short_string_cpy((ShortString)praw->sn,sizeof(praw->sn),(ShortString)&pdata[i]);
	if(LS_FAIL==ret){
		return LS_FAIL;
	}
	i+=ret;

//key
	if(i+1>data_len){
		return LS_FAIL;
	}	
	praw->rkey=pdata[i];

//	
	return LS_SUCCESS;
}

#define FP_QUEUE_LEN 5
static void *pg_fp_queue_message[FP_QUEUE_LEN];
static OS_EVENT *pg_fp_queue_hdl=NULL;

void fp_queue_create(void)
{
	pg_fp_queue_hdl=OSQCreate(pg_fp_queue_message,FP_QUEUE_LEN);
	if(NULL==pg_fp_queue_hdl){
		
	}
}

uint8_t fp_queue_post(void *pmsg)
{
	if(NULL==pg_fp_queue_hdl){
		return OS_ERR_Q_FULL;
	}
	return OSQPost(pg_fp_queue_hdl,pmsg);
}

void *fp_queue_receive(INT32U timeout)
{
	INT8U err;
	void *pmsg;
	
	if(NULL==pg_fp_queue_hdl){
		return NULL;
	}	
	pmsg=OSQPend(pg_fp_queue_hdl, timeout, &err);
	if(OS_ERR_NONE!=err){
	}
	return pmsg;
}

void fp_queue_flash(void)
{
	if(NULL==pg_fp_queue_hdl){
		return;
	}	
	
	OSQFlush(pg_fp_queue_hdl);
}

void task_fp_init(void)
{
	fp_queue_create();
}

typedef enum{
	FP_DISPLAY_DEEP,
	FP_DISPLAY_REAL_CALIBRATED,
	FP_DISPLAY_CRACK_CALIBRATED,
}FP_DISPLAY_CONTENT_E;

#define FP_CALIBRATED_TIMER_OVER 20

void task_fp_process(void *pdata)
{		
	uint32_t time_over;
	uint8_t depth;
	uint8_t buf[8];
	KEY_T *pkey;
	uint8_t calibrated;
	FP_DISPLAY_CONTENT_E display;
	bool b_real_data=TRUE;
	
	printf("[%s](%d) task created.\r\n",__FUNCTION__,__LINE__);
	
	pdata  = pdata; 
	fp_queue_flash();
	time_over=0;
	calibrated=0;
	display=FP_DISPLAY_DEEP;
	calibrated=0;
	for(;;){
		pkey=(KEY_T*)fp_queue_receive(OS_MS(100));
		if(NULL!=pkey){
#ifdef FP_TASK_DEBUG_ENABLE
			printf("status=%d,value=%d\r\n",pkey->status,pkey->value);
#endif	
			if(KS_DOWN==pkey->status){
				time_over=0;
				switch(pkey->value)
				{
					case KC_LEFT:
						b_real_data=TRUE;
						break;
					case KC_DOWN:
						if(b_real_data){
							display=FP_DISPLAY_REAL_CALIBRATED;
							calibrated=1;
							real_calibrate();
						}
						break;
					case KC_UP:
						if(FALSE==b_real_data){
							display=FP_DISPLAY_CRACK_CALIBRATED;
							calibrated=1;
							crack_calibrate();
						}
						break;
					case KC_RIGHT:
						b_real_data=FALSE;
						break;
				}
			}
		}	

		if(++time_over>FP_CALIBRATED_TIMER_OVER){
			time_over=0;
			if(0!=calibrated){
				calibrated=0;
				display=FP_DISPLAY_DEEP;
			}
		}


		if(b_real_data){
			fp_led_network(TRUE);
			fp_led_pid(FALSE);
			
		}else{
			fp_led_network(FALSE);
			fp_led_pid(TRUE);
		}			
		
		switch(display)
		{
		case FP_DISPLAY_DEEP:
			fp_beep(FALSE);
			if(b_real_data){
				depth=real_deep;
			}else{
				depth=crack_deep;
			}
			sprintf((char*)buf,"%4d",depth);
			panel_display(buf);
			break;
		case FP_DISPLAY_REAL_CALIBRATED:
			sprintf((char*)buf,"CBR1");
			fp_beep(TRUE);				
			panel_display(buf);				
			break;
		case FP_DISPLAY_CRACK_CALIBRATED:
			sprintf((char*)buf,"PJdd");
			panel_display(buf);		
			fp_beep(TRUE);
			break;
		}
	} 
}

KEY_CODE_E fp_key_get(uint8_t rkey)
{
	KEY_CODE_E value;
	switch(rkey)
	{
		case 1<<0:
			value=KC_LEFT;
			break;
		case 1<<1:
			value=KC_DOWN;
			break;
		case 1<<2:
			value=KC_UP;
			break;
		case 1<<3:
			value=KC_RIGHT;
			break;
		default:
			value=KC_BUTT;
			break;
	}
	return value;
}

void task_fp_update(void *pdata)
{	
#ifdef FP_TASK_DEBUG_ENABLE	
	int32_t i;
#endif	
	int32_t status;
	int32_t len;
	uint8_t cmd;
	uint8_t data[FP_DATA_LEN];
	int32_t data_len;
	KEY_RAW_T raw;
	uint8_t old_rkey;
	KEY_T key;
	
	pdata  = pdata; 
	
	printf("[%s](%d) task created.\r\n",__FUNCTION__,__LINE__);
#if 0//def TEST_ENABLE
	task_fp_test();
#endif

	old_rkey=0;
	for(;;){
		len=inner_packet_receive(FP_DEVICE,fp_receive_buf,sizeof(fp_receive_buf),FP_RECEIVE_TIMEOUT);
		if(len<INNER_PAD_LEN){
			memset(&g_ytdsp_info,0,sizeof(g_ytdsp_info));
			continue;
		}
		status=inner_extractor(fp_receive_buf,len,&cmd,data,&data_len);
		if(LS_SUCCESS!=status){
			continue;
		}
		
#ifdef FP_TASK_DEBUG_ENABLE
		printf("fp_received[%d]={",len);
		for(i=0;i<len;i++){
			printf("0x%02x,",fp_receive_buf[i]);
		}
		printf("}\r\n");
#endif
		switch(cmd)
		{
			case DSPCMD_KEYS_RECEIVED:
				fp_display();
				status=fp_keys_parse(data,data_len,&raw);
				if(LS_SUCCESS!=status){
					break;
				}	
				short_string_cpy((ShortString)g_ytdsp_info.sn,FP_SN_MAX,(ShortString)raw.sn);		
#if 0//def FP_TASK_DEBUG_ENABLE
				debug_printf("keys=0x%x\r\n",raw.rkey);
#endif
				if(raw.rkey){
					if(old_rkey!=raw.rkey){
						key.status=KS_DOWN;
					}else{
						key.status=KS_REPEAT;
					}
					key.value=fp_key_get(raw.rkey);
				}else{
					if(old_rkey!=raw.rkey){
						key.status=KS_UP;
					}else{
						key.status=KS_IDLE;
					}
					key.value=fp_key_get(old_rkey);
				}
				old_rkey=raw.rkey;
				if((KS_IDLE!=key.status)&&(KC_BUTT!=key.value)){
					if(OS_ERR_NONE!=fp_queue_post(&key)){
					}					
				}
				break;
			default:
				break;
		}
	} 
}

void fp_info_printf(void)
{
	ShortString pshstr;
	uint8_t u8len;
	char *p;
	
	printf("=======================================\r\n");
	pshstr=(ShortString)g_ytdsp_info.sn;
	if(TRUE==short_string_is_valid(pshstr)){
		short_string_content_len_get(pshstr,&p,&u8len);
		printf("ytdsp.sn[%d]={%s}\r\n",u8len,p);
	}else{
		printf("ytdsp.sn=NULL\r\n");
	}	
	printf("=======================================\r\n");	
}

#ifdef TEST_ENABLE
void fp_show_test(void)
{	
		panel_display("1234");
		fp_led_ytis(TRUE);
		fp_led_gps(TRUE);
		fp_led_network(TRUE);
		fp_led_pid(TRUE);
		fp_beep(FALSE);//TRUE
		sem_fp_pend();
		fp_display();
		sem_fp_post();
		
		sys_delay_ms(5000);
		
		panel_display("ABCD");
		fp_led_ytis(FALSE);
		fp_led_gps(FALSE);
		fp_led_network(FALSE);
		fp_led_pid(FALSE);
		fp_beep(FALSE);
		sem_fp_pend();
		fp_display();
		sem_fp_post();
		
		sys_delay_ms(5000);
	//}
	
}

void task_fp_test(void)
{
	fp_show_test();
}
#endif


